# -*- coding: utf-8 -*-
# # # # # # # # # # # # # # # # # # # # #
#                                       #
#    Trabajo Práctico 3 - Conexiones    #
#                                       #
#     Teoría de las Comunicaciones      #
#      Departamento de Computación      #
#              FCEN - UBA               #
#           octubre de 2013             #
#                                       #
# # # # # # # # # # # # # # # # # # # # #


import random

from client import PTCClientProtocol
from server import PTCServerProtocol


class PTCObject(object):

    def __init__(self, address, port = None):
        if port is None:
            port = random.randint(10000, 40000)
        self.protocol = self.protocol_class()(address, port)

    def __del__(self):
        try:
            self.close()
        except:
            pass

    def is_connected(self):
        return self.protocol.is_connected()

    def last_error(self):
        try:
            error = self.protocol.error
        except:
            error = str()
        return error


class PTCServer(PTCObject):

    def protocol_class(self):
        return PTCServerProtocol

    def recv(self, size):
        data = self.protocol.receive(size)
        return data

    def accept(self):
        if not self.protocol.is_connected():
            self.protocol.accept()
        else:
            raise Exception('already connected')

    def close(self, wait=True):
        if self.protocol.is_connected():
            if wait is True:
                self.close_wait()
            else:
                self.close_no_wait()

    def close_wait(self):
        self.protocol.wait_for_close()
        self.protocol.shutdown()

    def close_no_wait(self):
        if self.protocol.is_closed():
            self.protocol.shutdown()
        else:
            raise Exception('cannot close connection yet')


class PTCClient(PTCObject):

    def __init__(self, address, port, size):
       self.protocol = PTCClientProtocol(address, port, size)

    def protocol_class(self):
       raise Exception('Operation not supported exception')

    def send(self, data):
        self.protocol.send(data)

    def connect(self, address, port):
        if not self.protocol.is_connected():
            self.protocol.connect_to(address, port)
        else:
            raise Exception('already connected')

    def get_retrans_count(self):
        return self.protocol.get_retrans_count()
    
#    def write_tab_data(self):
#        self.protocol.write_tab_data()

    def wait_for_close(self):
        self.protocol.wait_for_close()

    def close(self):
        if self.protocol.is_connected():
            self.protocol.close()
